/**
 * ImageUpload - Image Upload Component with Drag & Drop
 * 
 * Features:
 * - Drag and drop image files
 * - Paste images from clipboard
 * - File picker
 * - Multiple image support
 * - Image preview
 * - Format validation (PNG, JPEG, WebP, GIF)
 * - Size limit (5MB per image)
 */

import { useRef, useState, useCallback, useEffect } from 'react';
import { Upload, X, Image as ImageIcon, GripVertical } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';

export interface ImageFile {
  id: string;
  file: File;
  preview: string;
  base64?: string;
}

export interface ImageUploadProps {
  maxImages?: number;
  maxSizeBytes?: number;
  onImagesChange: (images: ImageFile[]) => void;
  className?: string;
}

const ALLOWED_TYPES = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp', 'image/gif'];
const DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5MB

export function ImageUpload({
  maxImages = 5,
  maxSizeBytes = DEFAULT_MAX_SIZE,
  onImagesChange,
  className,
}: ImageUploadProps) {
  const [images, setImages] = useState<ImageFile[]>([]);
  const [dragActive, setDragActive] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [draggedImageId, setDraggedImageId] = useState<string | null>(null);
  const [dragOverImageId, setDragOverImageId] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // Process files and convert to base64
  const processFiles = useCallback(async (files: File[]) => {
    setError(null);
    const validFiles: ImageFile[] = [];

    for (const file of files) {
      // Check file type
      if (!ALLOWED_TYPES.includes(file.type)) {
        setError(`不支持的文件类型: ${file.type}`);
        continue;
      }

      // Check file size
      if (file.size > maxSizeBytes) {
        setError(`文件过大: ${file.name} (最大 ${maxSizeBytes / 1024 / 1024}MB)`);
        continue;
      }

      // Check max images limit
      if (images.length + validFiles.length >= maxImages) {
        setError(`最多只能上传 ${maxImages} 张图片`);
        break;
      }

      // Create preview URL
      const preview = URL.createObjectURL(file);

      // Convert to base64
      const base64 = await fileToBase64(file);

      validFiles.push({
        id: `${Date.now()}-${Math.random()}`,
        file,
        preview,
        base64,
      });
    }

    if (validFiles.length > 0) {
      const newImages = [...images, ...validFiles];
      setImages(newImages);
      onImagesChange(newImages);
    }
  }, [images, maxImages, maxSizeBytes, onImagesChange]);

  // Convert file to base64
  const fileToBase64 = (file: File): Promise<string> => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => {
        const base64 = reader.result as string;
        // Remove data:image/...;base64, prefix
        const base64Data = base64.split(',')[1];
        resolve(base64Data);
      };
      reader.onerror = reject;
    });
  };

  // Handle file input change
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    processFiles(files);
    // Reset input
    if (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
  };

  // Handle drag events
  const handleDrag = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === 'dragenter' || e.type === 'dragover') {
      setDragActive(true);
    } else if (e.type === 'dragleave') {
      setDragActive(false);
    }
  };

  // Handle drop
  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);

    const files = Array.from(e.dataTransfer.files);
    processFiles(files);
  };

  // Handle paste
  const handlePaste = useCallback((e: ClipboardEvent) => {
    const items = e.clipboardData?.items;
    if (!items) return;

    const files: File[] = [];
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (item.type.indexOf('image') !== -1) {
        const file = item.getAsFile();
        if (file) files.push(file);
      }
    }

    if (files.length > 0) {
      processFiles(files);
    }
  }, [processFiles]);

  // Remove image
  const removeImage = (id: string) => {
    const newImages = images.filter(img => img.id !== id);
    setImages(newImages);
    onImagesChange(newImages);

    // Revoke object URL to free memory
    const image = images.find(img => img.id === id);
    if (image) {
      URL.revokeObjectURL(image.preview);
    }
  };

  // Listen to paste events
  useEffect(() => {
    window.addEventListener('paste', handlePaste);
    return () => window.removeEventListener('paste', handlePaste);
  }, [handlePaste]);

  // Handle image drag start (for reordering)
  const handleImageDragStart = (e: React.DragEvent, imageId: string) => {
    setDraggedImageId(imageId);
    e.dataTransfer.effectAllowed = 'move';
  };

  // Handle image drag over (for reordering)
  const handleImageDragOver = (e: React.DragEvent, imageId: string) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'move';
    setDragOverImageId(imageId);
  };

  // Handle image drop (for reordering)
  const handleImageDrop = (e: React.DragEvent, targetImageId: string) => {
    e.preventDefault();
    if (!draggedImageId || draggedImageId === targetImageId) {
      setDraggedImageId(null);
      setDragOverImageId(null);
      return;
    }

    const draggedIndex = images.findIndex(img => img.id === draggedImageId);
    const targetIndex = images.findIndex(img => img.id === targetImageId);

    if (draggedIndex === -1 || targetIndex === -1) return;

    const newImages = [...images];
    const [draggedImage] = newImages.splice(draggedIndex, 1);
    newImages.splice(targetIndex, 0, draggedImage);

    setImages(newImages);
    onImagesChange(newImages);
    setDraggedImageId(null);
    setDragOverImageId(null);
  };

  // Handle image drag end (for reordering)
  const handleImageDragEnd = () => {
    setDraggedImageId(null);
    setDragOverImageId(null);
  };

  return (
    <div className={cn('space-y-2', className)}>
      {/* Upload Area */}
      <div
        onDragEnter={handleDrag}
        onDragLeave={handleDrag}
        onDragOver={handleDrag}
        onDrop={handleDrop}
        className={cn(
          'relative border-2 border-dashed rounded-lg p-4 transition-colors',
          'hover:border-primary/50 hover:bg-accent/50',
          dragActive && 'border-primary bg-accent',
          images.length >= maxImages && 'opacity-50 cursor-not-allowed'
        )}
      >
        <input
          ref={fileInputRef}
          type="file"
          accept={ALLOWED_TYPES.join(',')}
          multiple
          onChange={handleFileChange}
          disabled={images.length >= maxImages}
          className="sr-only"
        />

        <div className="flex flex-col items-center justify-center gap-2 text-center">
          <Upload className={cn(
            'w-8 h-8 text-muted-foreground transition-colors',
            dragActive && 'text-primary'
          )} />
          
          <div className="text-sm">
            <Button
              type="button"
              variant="link"
              className="p-0 h-auto"
              onClick={() => fileInputRef.current?.click()}
              disabled={images.length >= maxImages}
            >
              点击上传
            </Button>
            <span className="text-muted-foreground"> 或拖拽图片到此处</span>
          </div>

          <p className="text-xs text-muted-foreground">
            支持 PNG, JPEG, WebP, GIF • 最大 {maxSizeBytes / 1024 / 1024}MB • 最多 {maxImages} 张
          </p>

          {images.length > 0 && (
            <p className="text-xs text-primary">
              已上传 {images.length} / {maxImages} 张
            </p>
          )}
        </div>
      </div>

      {/* Error Message */}
      {error && (
        <div className="text-sm text-destructive bg-destructive/10 px-3 py-2 rounded-md">
          {error}
        </div>
      )}

      {/* Image Previews */}
      {images.length > 0 && (
        <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-2">
          {images.map((image, index) => (
            <div
              key={image.id}
              draggable
              onDragStart={(e) => handleImageDragStart(e, image.id)}
              onDragOver={(e) => handleImageDragOver(e, image.id)}
              onDrop={(e) => handleImageDrop(e, image.id)}
              onDragEnd={handleImageDragEnd}
              className={cn(
                "group relative aspect-square rounded-lg overflow-hidden border bg-muted cursor-move transition-all",
                draggedImageId === image.id && "opacity-50 scale-95",
                dragOverImageId === image.id && "ring-2 ring-primary ring-offset-2"
              )}
            >
              <img
                src={image.preview}
                alt={image.file.name}
                className="w-full h-full object-cover pointer-events-none"
              />
              
              {/* Drag Handle */}
              <div className="absolute top-1 left-1 bg-black/50 rounded p-1 opacity-0 group-hover:opacity-100 transition-opacity cursor-grab active:cursor-grabbing">
                <GripVertical className="w-3 h-3 text-white" />
              </div>

              {/* Image Index */}
              <div className="absolute top-1 right-1 bg-black/70 text-white text-xs px-1.5 py-0.5 rounded">
                {index + 1}
              </div>
              
              {/* Overlay */}
              <div className="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
                <Button
                  type="button"
                  variant="destructive"
                  size="icon"
                  className="h-8 w-8"
                  onClick={() => removeImage(image.id)}
                >
                  <X className="w-4 h-4" />
                </Button>
              </div>

              {/* File info */}
              <div className="absolute bottom-0 left-0 right-0 bg-black/70 text-white text-xs p-1 truncate opacity-0 group-hover:opacity-100 transition-opacity">
                {image.file.name}
              </div>
            </div>
          ))}
        </div>
      )}

      {/* Paste Hint */}
      {images.length < maxImages && (
        <p className="text-xs text-muted-foreground text-center">
          💡 提示：你也可以直接 <kbd className="px-1 py-0.5 bg-muted rounded text-xs">Ctrl+V</kbd> 粘贴图片
        </p>
      )}
    </div>
  );
}

